import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { ConfigService } from "@nestjs/config";
import { objConvert } from "st-common-core";
import { EnvNameEnum } from "../common/env";
import { RedisKeyConst, set, getWithParse } from "../common/redis";
import { Role } from "./entities/Role";
import { RootRoleInfoConst } from "./consts/root-role-info.const";
import { RoleEntityPropNameEnum } from "./enums/role-entity-prop-name.enum";
import { RoleFilterFieldNameEnum } from "./enums/role-filter-field-name.enum";
import { RoleVO, RoleVoDefault } from './vos/role.vo'

/**
 * 角色服务
 */
@Injectable()
export class RoleService {

  private readonly logger = new Logger(RoleService.name);

  constructor(
    @InjectRepository(Role)
    private readonly roleRepository: Repository<Role>,
    private readonly configService: ConfigService
  ) {
  }

  /**
   * 创建超级管理员角色<br/>
   * 如果数据库中不存在超级管理员角色，则创建并返回，否则直接返回数据库中的超级管理员角色<br/>
   *
   * @returns {Promise<Role>} 超级管理员角色
   */
  async createRoot(): Promise<Role> {
    // 从数据库中获取 root 角色
    let rootRole = await this.roleRepository.findOne({
      where: {
        [RoleEntityPropNameEnum.CODE]: this.configService.get<string>(EnvNameEnum.ROOT_ROLE_CODE) ?? RootRoleInfoConst.CODE
      }
    });
    // 如果 root 角色不存在，则创建
    if (!rootRole) {
      this.logger.log("超级管理员角色不存在，开始创建...");
      rootRole = {
        [RoleEntityPropNameEnum.NAME]: this.configService.get<string>(EnvNameEnum.ROOT_ROLE_NAME) ?? RootRoleInfoConst.NAME,
        [RoleEntityPropNameEnum.CODE]: this.configService.get<string>(EnvNameEnum.ROOT_ROLE_CODE) ?? RootRoleInfoConst.CODE,
        [RoleEntityPropNameEnum.REMARK]: this.configService.get<string>(EnvNameEnum.ROOT_ROLE_REMARK) ?? RootRoleInfoConst.REMARK
      } as Role;
      rootRole = await this.roleRepository.save(rootRole);
      this.logger.log("超级管理员角色创建成功！");
    }
    return rootRole;
  }

  /**
   * 从数据库中获取所有角色并缓存到 Redis 中
   *
   * @returns {Promise<RoleVO[] | null>} 角色列表，如果发生了错误则返回 null
   */
  async findAllFromDBAndCache(): Promise<RoleVO[] | null> {
    // 从数据库中获取所有角色
    const roles = await this.roleRepository.find();
    // 将查询出来的角色列表中的 Role 类型转化为 RoleVo 类型
    const roleVos = roles.map(role => {
      const roleVo = { ...RoleVoDefault };
      return objConvert<RoleVO>(role, roleVo);
    });
    // 将角色列表缓存到 Redis 中
    const res = await set({
      key: RedisKeyConst.ROLE_ALL(),
      value: roles
    });
    // 返回角色列表，如果发生了错误则返回 null
    return res ? roles : null;
  }

  /**
   * 根据过滤条件查询角色<br/>
   * 如果在 Redis 中缓存了角色列表，则优先从 Redis 中获取角色列表，否则从数据库中获取角色列表并缓存到 Redis 中<br/>
   *
   * @param {Record<string, any>} filters 过滤条件
   * @returns {Promise<RoleVO[]>} 角色列表，如果发生了错误则返回 null
   */
  async find(filters: Record<string, any> = {}) {
    // 尝试从 Redis 中获取角色列表
    let roles = await getWithParse<RoleVO[]>(RedisKeyConst.ROLE_ALL());
    // 如果 Redis 中没有缓存，则从数据库中获取角色列表并缓存到 Redis 中
    if (!roles) roles = await this.findAllFromDBAndCache();
    // 如果仍然获取失败
    if (!roles) return null;
    // 如果没有过滤条件，则直接返回角色列表
    if (Object.keys(filters).length === 0) return roles;
    // 过滤角色列表
    return roles.filter(role => {
      for (const [key, value] of Object.entries(filters)) {
        // 如果当前的过滤条件不在允许的字段中，则跳过当前条件的过滤
        if (!(Object.values(RoleFilterFieldNameEnum) as string[]).includes(key)) continue;
        // 当前角色的属性值
        let rolePropVal = role[key];
        if (key === RoleEntityPropNameEnum.NAME || key === RoleEntityPropNameEnum.CODE) {
          // 忽略大小写
          rolePropVal = rolePropVal.toLowerCase();
          if (!rolePropVal.includes(value.toLowerCase())) return false;
        } else {
          if (typeof value === "boolean") rolePropVal = Boolean(rolePropVal);
          if (rolePropVal !== value) return false;
        }
      }
      return true;
    });
  }

  async save() {

  }

}
